#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <cJSON.h>

#define N 256
//#define FILE_ADDR "~/lianxi/wangguan/hq_plat/app/node.json"
#define FILE_ADDR "/home/hq/lianxi/xianmu/hq_plat/app/node.json"
// #define MQTT_ADDR "192.168.28.15"
// #define MQTTclifd

/*struct msgjsoclifd
{
    int type;
    int result;clifd
    char up_config[10];
    char addr[32]; 
    union val_t val;
}; */

pthread_t tid;

void *hander(void *arg)
{
    int clifd = *(int *)arg;
    printf("tid:%d\n",tid);
    printf("clifd:%d\n",clifd);
    /*接受node.json文件 */
    int ret = 0;
    char get_buf[N] = {0};
    char *put_buf = NULL;
    int type=0, file_len = 0;
    char *data_flag = NULL;
    int file_size;
    char node_json[4096] = {0};
    int fd_file;
    cJSON *get_root = NULL,*put_root = NULL, *get_data = NULL, *put_data = NULL;
    //cJSON *mqtt_config = NULL, *update_config = NULL;
    //put_root = cJSON_CreateObject();
    //put_data = cJSON_CreateObject();
    //cJSON_AddItemToObject(put_root, "data", put_data);
    // cJSON_AddItemToObject(put_data, "mqtt_config", mqtt_config);
    // cJSON_AddItemToObject(put_data, "update_config", update_config);
    
    //for(int a=0;a<30;a++)
    while(1)
    {
        ret = recv(clifd, get_buf, N, 0);
        if(ret <= 0)
        {
            perror("recv err");
            //continue;
            return;
        }
        //printf("buf:%s\n",get_buf);
        get_root = cJSON_Parse(get_buf);
        if (get_root == NULL)
        {
            printf("Error before: [%s]\n", cJSON_GetErrorPtr());
            cJSON_Delete(get_root);
            printf("发送内容非json格式请检查\n");
            sleep(2);
            //return -1;
            continue;
        }
        else
        {
            if(cJSON_GetObjectItem(get_root, "type") == NULL)
            {
                printf("Error before: [%s]\n", cJSON_GetErrorPtr());
                cJSON_Delete(get_root);
                printf("发送内容非json格式请检查\n");
                sleep(2);
                //return -1;
                continue;
            }
        }
        
        type = cJSON_GetObjectItem(get_root, "type")->valueint;
        //printf("type:%d\n",type);
        if(type == 1)
        {
            put_root = cJSON_CreateObject();
            cJSON_AddNumberToObject(put_root, "type", 1);
            cJSON_AddNumberToObject(put_root, "result", 0);
            fd_file = open(FILE_ADDR, O_RDONLY);
            if(fd_file < 0)
            {
                cJSON_AddTrueToObject(put_root, "up_config");//在对象中添加true
            }
            else
            {
                cJSON_AddFalseToObject(put_root, "up_config");
            }
            put_buf = cJSON_Print(put_root);
            printf("put_buf:%s\n",put_buf);
            send(clifd, put_buf, N, 0);
            /*cJSON_DetachItemFromObject(put_root, "type");
            cJSON_DetachItemFromObject(put_root, "result");
            cJSON_DetachItemFromObject(put_root, "up_config"); */
            cJSON_Delete(put_root);
        }
        else if(type == 2)
        {
            get_data = cJSON_GetObjectItem(get_root, "data");
            file_len = cJSON_GetObjectItem(get_data, "file_len")->valueint;
            data_flag = cJSON_GetObjectItem(get_data, "flag")->valuestring;
            if(strcmp(data_flag,"start") == 0)
            {
                fd_file = open(FILE_ADDR, O_RDWR|O_CREAT|O_TRUNC, 0666);
                if (fd_file < 0)
                {
                    perror("open file err");
                    return;
                }
                put_root = cJSON_CreateObject();
                put_data = cJSON_CreateObject();
                cJSON_AddNumberToObject(put_root, "type", 2);
                cJSON_AddItemToObject(put_root, "data", put_data);
                cJSON_AddStringToObject(put_data, "flag", "start");
                //char c[64] = "{\"type\":2,\"data\":{\"flag\":\"start\"}}";
                //strcpy(put_buf,c);
                put_buf = cJSON_Print(put_root);
                send(clifd, put_buf, N, 0);
                printf("put_buf111:%s\n",put_buf);
                //cJSON_Delete(put_data);
                cJSON_Delete(put_root);
                
                file_size = recv(clifd, node_json, 4096,0);
                if(ret < 0)
                {
                    perror("recv err");
                    //continue;
                    return;
                }
                fd_file = write(fd_file, node_json, file_size);
                if (fd_file < 0)
                {
                    perror("write file err");
                    return;
                }
                put_root = cJSON_CreateObject();
                put_data = cJSON_CreateObject();
                cJSON_AddNumberToObject(put_root, "type", 2);
                cJSON_AddItemToObject(put_root, "data", put_data);
                cJSON_AddStringToObject(put_data, "flag", "stop");
                put_buf = cJSON_Print(put_root);
                //bzero(put_buf,sizeof(put_buf));
                //char c1[64] = "{\"type\":2,\"data\":{\"flag\":\"stop\"}}";
                //strcpy(put_buf,c1);
                send(clifd, put_buf, N, 0);
                printf("put_buf222:%s\n",put_buf);
                //cJSON_Delete(put_data);
                cJSON_Delete(put_root);
            }   
        }
        else if(type == 3)
        {
            put_root = cJSON_CreateObject();
            cJSON_AddNumberToObject(put_root, "type", 3);
            cJSON_AddNumberToObject(put_root, "result", 0);
            put_buf = cJSON_Print(put_root);
            send(clifd, put_buf, N, 0);
            // cJSON_DetachItemFromObject(put_root, "type");
            // cJSON_DetachItemFromObject(put_root, "result");
            cJSON_Delete(put_root);
        }
        cJSON_Delete(get_root);
    } 

    //cJSON_Delete(get_root);
    cJSON_Delete(put_root);
    cJSON_Delete(put_data);
    pthread_join(tid, NULL);
}

int main(int argc, char const *argv[])
{
    int broadfd;
    //创建一个socket文件描述符
    broadfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(broadfd < 0)
    {
        perror("sock err");
        return -1;
    }

    //绑定套接字(ip+port)
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8878);  //端口号
    addr.sin_addr.s_addr = INADDR_ANY;
    int addrlen = sizeof(addr);
    
    if(bind(broadfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    ssize_t len;
    char buf[N] = {0};
    
    struct sockaddr_in cliaddr;
    
    //接收"coffee"搜索包
    bzero(buf, N);
    len = recvfrom(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);

    //判断是否是本公司产品：收到的数据是否"coffee"
    if(strcmp(buf, "hqdevice") != 0)
    {
        printf("not hq device\n");
        return -1;
    }
    //回复yes，告诉软件，我收到了搜索协议，并且回复clifd地址
    sendto(broadfd, "yes", 4, 0, (struct sockaddr *)&cliaddr, addrlen);

    //变身为TCP服务器，准备接收软件的升级文件
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if(tcpfd < 0)
    {
        perror("sock err");
        return -1;
    }

    if(bind(tcpfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    //监听套接字
    if(listen(tcpfd, 5) < 0)
    {
        perror("listen err");
        return -1;
    }

    //接收客户端的连接
    printf("wait client connect\n");
    int clifd;
    //接收对端的地址
    while(1)
    {
        clifd = accept(tcpfd, (struct sockaddr *)&cliaddr, &addrlen);//接收客户端的请求，阻塞接口
        if(clifd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("new TCPcononect coming\n");
        
        if (pthread_create(&tid, NULL, hander, &clifd))
        {
            perror("thread create err");
            return -1;
        }
    }

    //while(1);
    
    close(clifd);
    close(broadfd);
    return 0;
}
